#ifndef STX_PLATFORM_POSIX_THREAD_MUTEX_ATTRIBUTES_HPP
#define STX_PLATFORM_POSIX_THREAD_MUTEX_ATTRIBUTES_HPP

#include <stx/platform/posix/thread/common.hpp>

namespace stx {

namespace posix {

class mutex_attributes: noncopyable
{
public:
    
    typedef mutex_attributes this_type;
    
    mutex_attributes()
    {
        int ret = pthread_mutexattr_init(&handle_);
        if (ret) {
            STX_THROW_SYSTEM_ERROR_VAL(ret, "pthread_mutexattr_init");
        }
    }
    
    ~mutex_attributes()
    {
        int ret = pthread_mutexattr_destroy(&handle_);
        if (ret) {
            STX_DESTRUCTOR_SYSTEM_ERROR_VAL(ret, "pthread_mutexattr_destroy");
        }
    }
    
    #if STX_HAS_PTHREAD_MUTEXATTR_GETPRIOCEILING
    int priority_ceiling() const
    {
        int val;
        int ret = pthread_mutexattr_getprioceiling(&handle_, &val);
        if (ret) {
            STX_THROW_SYSTEM_ERROR_VAL(ret, "pthread_mutexattr_getprioceiling");
        }
        return val;
    }
    #endif
    
    #if STX_HAS_PTHREAD_MUTEXATTR_SETPRIOCEILING
    this_type& set_priority_ceiling(int val)
    {
        int ret = pthread_mutexattr_setprioceiling(&handle_, val);
        if (ret) {
            STX_THROW_SYSTEM_ERROR_VAL(ret, "pthread_mutexattr_setprioceiling");
        }
        return *this;
    }
    #endif
    
    //  Values:
    //      PTHREAD_PRIO_NONE
    //      PTHREAD_PRIO_INHERIT
    //      PTHREAD_PRIO_PROTECT
    #if STX_HAS_PTHREAD_MUTEXATTR_GETPROTOCOL
    int protocol() const
    {
        int val;
        int ret = pthread_mutexattr_getprotocol(&handle_, &val);
        if (ret) {
            STX_THROW_SYSTEM_ERROR_VAL(ret, "pthread_mutexattr_getprotocol");
        }
        return val;
    }
    #endif
    
    #if STX_HAS_PTHREAD_MUTEXATTR_SETPROTOCOL
    this_type& set_protocol(int val)
    {
        int ret = pthread_mutexattr_setprotocol(&handle_, val);
        if (ret) {
            STX_THROW_SYSTEM_ERROR_VAL(ret, "pthread_mutexattr_setprotocol");
        }
        return *this;
    }
    #endif
    
    //  Values:
    //      PTHREAD_PROCESS_SHARED
    //      PTHREAD_PROCESS_PRIVATE
    int process_shared() const
    {
        int val;
        int ret = pthread_mutexattr_getpshared(&handle_, &val);
        if (ret) {
            STX_THROW_SYSTEM_ERROR_VAL(ret, "pthread_mutexattr_getpshared");
        }
        return val;
    }
    
    this_type& set_process_shared(int val)
    {
        int ret = pthread_mutexattr_setpshared(&handle_, val);
        if (ret) {
            STX_THROW_SYSTEM_ERROR_VAL(ret, "pthread_mutexattr_setpshared");
        }
        return *this;
    }
    
    //  Values:
    //      PTHREAD_MUTEX_NORMAL
    //      PTHREAD_MUTEX_ERRORCHECK
    //      PTHREAD_MUTEX_RECURSIVE
    //      PTHREAD_MUTEX_DEFAULT
    int type() //const // const qualifier fails with pthreads-win32 library
    {
        int val;
        int ret = pthread_mutexattr_gettype(&handle_, &val);
        if (ret) {
            STX_THROW_SYSTEM_ERROR_VAL(ret, "pthread_mutexattr_gettype");
        }
        return val;
    }
    
    this_type& set_type(int val)
    {
        int ret = pthread_mutexattr_settype(&handle_, val);
        if (ret) {
            STX_THROW_SYSTEM_ERROR_VAL(ret, "pthread_mutexattr_settype");
        }
        return *this;
    }
    
    typedef pthread_mutexattr_t handle_type;
    
    handle_type* handle()
    {
        return &handle_;
    }
    
    const handle_type* handle() const
    {
        return &handle_;
    }
    
private:
    
    handle_type handle_;
};

} // namespace posix

} // namespace stx

#endif // STX_PLATFORM_POSIX_THREAD_MUTEX_ATTRIBUTES_HPP
